1.5.1. Creating a Token Policy
A token policy defines the
ACS token-issuing policy. You can create the token policy for the
ACSMachineInfo example using Acm.exe as follows:
acm.exe create tokenpolicy -name:acsexample -autogeneratekey
-service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
I'm using the default
token lifetime of 28888 seconds (8 hours). The autogeneratekey
parameter indicates that I'm relying on ACS to autogenerate an
HMAC-SHA256 signed key for issuing tokens. One service namespace can
contain many token policies.
1.5.2. Creating a scope
A scope is used to group
settings of a particular resource. When you create a scope, you assign
a token policy ID to it. The Acm.exe command to create a scope in the
ACSMachineInfo example is as follows:
acm.exe create scope -name:acsexample -appliesto:
http://localhost/acsexample/ -tokenpolicyid:%tokenpolicyid%
-service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
This command defines a
scope named acsexample. The appliesto parameter specifies the URI of
the resource for which you want to specify the access control rules.
Note that it accepts the tokenpolicyid created by the previous command.
1.5.3. Creating an Issuer
An issuer describes the
cryptographic key material that a web service client uses to acquire
ACS tokens. In the ACSMachineInfo example, the web service client
creates an SWT token and then sends that token to ACS to acquire
another SWT token to send to the web service. In this case, the web
service client becomes an issuer of the first SWT token. The Acm.exe
command to create an issuer in the ACSMachineInfo example is as follows:
acm.exe create issuer -name:acs
example -issuername:acsexample -autogeneratekey -service:%acsolution%
-mgmtkey:%acmgmtkey% -simpleout
In this command, the web
service client needs to identify itself as the acsexample issuer client
when requesting an SWT from ACS. The default algorithm used to generate
a key is Symmetrick256Key and X.509. This example uses the default
value because typically, the X.509 value is used to issu SAML tokens
from ADFS v2.0.
1.5.4. Creating Rules
After the token policy,
scope, and issuer are configured, you can create rules that map the
input claims coming from the token issued by the issuer to output
claims ACS creates in the token it issues back to the caller. A rule is
the logic that needs to be executed on a certain set of input claims to
produce a set of output claims. These output claims are validated by
the web service (relying party) while granting appropriate access to
the caller. As discussed earlier, in the ACSMachineInfo example, four
rules need to be configured. The Acm.exe commands to create the
required rules are shown in Listing 2.
Example 2. Creating Rules
acm.exe create rule -name:acsexamplegetmachinename -scopeid:%scopeid% - inclaimissuerid:%issuerid% -inclaimtype:group -inclaimvalue:user - outclaimtype:action -outclaimvalue:getmachinename -service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
acm.exe create rule -name:acsexamplegetuserdomainname -scopeid:%scopeid% - inclaimissuerid:%issuerid% -inclaimtype:group -inclaimvalue:user - outclaimtype:action -outclaimvalue:getuserdomainname -service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
acm.exe create rule -name:acsexamplegetosversion -scopeid:%scopeid% - inclaimissuerid:%issuerid% -inclaimtype:group -inclaimvalue: user -outclaimtype:action - outclaimvalue:getosversion -service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
acm.exe create rule -name:acsexampleencodestring -scopeid:%scopeid% - inclaimissuerid:%issuerid% -inclaimtype:group -inclaimvalue:admin -outclaimtype:action - outclaimvalue:encodestring -service:%acsolution% -mgmtkey:%acmgmtkey% -simpleout
|
The create rule parameter of
Acm.exe creates a rule that defines the name of the rule, the input
claim type and value, and the output client type and value. For each
mapping defined, ACS includes the output claim in the token it issues.
1.5.5. Creating or Modifying the Relying Party to Accept an SWT from ACS
After you configure ACS, ACS
can issue tokens for the web service. But you must still modify the web
service to recognize and validate the token and the rules issued in the
token. The web service code must do the following things to be
compatible with ACS:
Verify the presence of the token issued by ACS.
Check if the token is signed with the appropriate key.
Verify that the token contains the claims it expects.
Grant appropriate access to the user depending on the claims.
The Service project in the
Visual Studio solution represents the web service implementation.
Because the ACSMachineInfo web service is based on WCF, you can create
a custom authorization manager inheriting from the
ServiceAuthorizationManager class and inject the necessary logic to
validate token content automatically. Listing 3 shows the implementation of ACSAuthorizationManager.
Example 3. ACSAuthorizationManager
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.ServiceModel; using System.ServiceModel.Web;
public class ACSAuthorizationManager : ServiceAuthorizationManager { TokenValidator validator; string requiredClaimType;
public ACSAuthorizationManager(string acsHostName, string trustedSolution, string trustedAudienceValue, byte[] trustedSigningKey, string requiredClaimType) { this.validator = new TokenValidator(acsHostName, trustedSolution, trustedAudienceValue, trustedSigningKey); this.requiredClaimType = requiredClaimType; }
protected override bool CheckAccessCore(OperationContext operationContext) { // get the authorization header string authorizationHeader = WebOperationContext.Current.IncomingRequest .Headers[HttpRequestHeader.Authorization];
if (string.IsNullOrEmpty(authorizationHeader)) { WebOperationContext.Current.OutgoingResponse.Status Code = HttpStatusCode.Unauthorized; return false; }
// validate the token if (!this.validator.Validate(authorizationHeader)) { WebOperationContext.Current.OutgoingResponse.Status Code = HttpStatusCode.Unauthorized; return false;
}
// check for an action claim and get the value Dictionary<string, string> claims = this.validator. GetNameValues(authorizationHeader);
// use the operation name to determine the requried action value string requiredActionClaimValue = WebOperationContext.Current. IncomingRequest.UriTemplateMatch.RelativePathSegments.First();
string actionClaimValue; if (!claims.TryGetValue(this.requiredClaimType, out actionClaimValue)) { WebOperationContext.Current.OutgoingResponse.Status Code = HttpStatusCode.Unauthorized; return false; }
// check for "," delimited values string[] actionClaimValues = actionClaimValue.Split(',');
// check for the correct action claim value if (!actionClaimValues.Contains(requiredActionClaimValue)) { WebOperationContext.Current.OutgoingResponse.Status Code = HttpStatusCode.Unauthorized; return false; }
return true; } }
|
The CheckAccessCore method
validates the token, gets the list of claims in the token, and then
checks if the claims are valid for executing the particular operation.
The TokenValidator class contains a method to validate the token. The
ACSAuthorizationManager class instantiates TokenValidator in its
constructor and then calls the Validate() method to validate the token.
The TokenValidator class also returns the claims from the
GetNameValues() method. The CheckAccessCore() method then checks if the
claims contain the action corresponding to the method being called by
the user. If the claims contain the action being called, the method
returns true; otherwise, the method returns false.